package com.lofter.heras.ui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.security.DigestException;
import java.security.NoSuchAlgorithmException;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import com.lofter.heras.hash.Hash;
import com.lofter.heras.hash.ProgressBarHandler;

public class HashFile extends JFrame implements ActionListener, ChangeListener,
		DropTargetListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1957318512056894847L;
	private Hash hash;
	private static final int WINDOW_WIDTH = 800;
	private static final int WINDOW_HEIGHT = 600;

	public HashFile() {
		init();
	}

	public JFileChooser getFileChoose() {
		return fileChoose;
	}

	/**
	 * command mode
	 */
	public boolean commandMode = false;

	/**
	 * run in command mode.
	 * 
	 * @param file
	 * @param hash
	 */
	public void run(String file, String hash) {
		if (commandMode) {
			boolean ret = false;
			if (file != null) {
				File tmp = null;
				try {
					tmp = new File(file);
					if (false == tmp.exists() && tmp.isFile()) {
						ret = true;
					}
				} catch (Exception e) {
					ret = true;
				}
				if (ret) {
					return;
				}
				final String f = (tmp == null) ? "" : tmp.getAbsolutePath();
				pathField.setText(f);
				String path = pathField.getText();
				if (path.length() > 0) {
					if (false == ("md5".equalsIgnoreCase(hash) || "sha1"
							.equalsIgnoreCase(hash))) {
						hash = "md5";
					}
					State.hashType = hash;
					start(path);
				}
			}
		}
	}

	private void init() {
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		Dimension screenSize = toolkit.getScreenSize();
		// center of the screen
		int x = (screenSize.width - WINDOW_WIDTH) / 2;
		int y = (screenSize.height - WINDOW_HEIGHT) / 2;
		this.setLocation(x, y);
		this.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.setLayout(new BorderLayout());
		this.setTitle("Hash File(v1)");
		this.setResizable(false);

		JPanel topPanel = new JPanel();
		topPanel.setPreferredSize(new Dimension(WINDOW_WIDTH, 40));
		topPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
		this.add(topPanel, BorderLayout.NORTH);
		pathField = new JTextField();
		pathField.setPreferredSize(new Dimension(WINDOW_WIDTH - 80, 30));
		pathField.setEditable(false);
		topPanel.add(pathField);

		btnBrowse = new JButton("...");
		btnBrowse.setActionCommand("browse");
		btnBrowse.setPreferredSize(new Dimension(50, 30));
		btnBrowse.addActionListener(this);
		topPanel.add(btnBrowse);

		JPanel bottomPanel = new JPanel();
		bottomPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
		bottomPanel.setPreferredSize(new Dimension(WINDOW_WIDTH, 40));
		this.add(bottomPanel, BorderLayout.SOUTH);

		progressBar = new JProgressBar();
		progressBar.setPreferredSize(new Dimension(WINDOW_WIDTH - 300, 30));
		progressBar.setMaximum(100);
		progressBar.setMinimum(0);
		progressBar.setValue(0);
		progressBar.setStringPainted(true);
		progressBar.setString("0/0(0%)");
		bottomPanel.add(progressBar);

		radMd5 = new JRadioButton("MD5");
		radMd5.setActionCommand("md5");
		radMd5.setPreferredSize(new Dimension(50, 30));
		radMd5.addChangeListener(this);
		bottomPanel.add(radMd5);
		radSHA1 = new JRadioButton("SHA1");
		radSHA1.setActionCommand("sha1");
		radSHA1.addChangeListener(this);
		radSHA1.setPreferredSize(new Dimension(60, 30));
		radMd5.setSelected(true);
		bottomPanel.add(radSHA1);

		btnStart = new JButton("Start");
		btnStart.setActionCommand("start");
		btnStart.addActionListener(this);
		btnStart.setPreferredSize(new Dimension(70, 30));
		bottomPanel.add(btnStart);

		btnCopy = new JButton("Copy");
		btnCopy.setActionCommand("copy");
		btnCopy.addActionListener(this);
		btnCopy.setPreferredSize(new Dimension(70, 30));
		bottomPanel.add(btnCopy);

		JScrollPane logPane = new JScrollPane();
		logPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		logPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		logField = new JTextArea();
		logField.setEditable(false);
		logField.setWrapStyleWord(false);
		logField.setLineWrap(true);
		logPane.setViewportView(logField);
		this.add(logPane, BorderLayout.CENTER);

		fileChoose = new JFileChooser();
		fileChoose.setFileHidingEnabled(false);
		hash = Hash.getInstance();
		hash.setHandler(new ProgressBarHandler(progressBar));

		new DropTarget(logField, DnDConstants.ACTION_COPY_OR_MOVE, this);
	}

	@Override
	public void actionPerformed(ActionEvent event) {
		if (false == State.running) {
			String command = event.getActionCommand();
			switch (command) {
			case "start":
				State.hashType = radMd5.isSelected() ? "md5" : "sha1";
				String path = pathField.getText();
				if (path.length() > 0) {
					start(path);
				}
				break;
			case "copy":
				if (State.hashCode.length() > 0) {
					Clipboard clipboard = Toolkit.getDefaultToolkit()
							.getSystemClipboard();
					Transferable transferable = new StringSelection(
							State.hashCode);
					clipboard.setContents(transferable, null);
					JOptionPane.showMessageDialog(HashFile.this,
							"The hash code has been copyed to the clipboard!");
				}
				break;
			case "browse":

				int result = fileChoose.showOpenDialog(this);
				if (result == JFileChooser.APPROVE_OPTION) {
					pathField.setText(fileChoose.getSelectedFile()
							.getAbsolutePath());
				}

				break;
			}
		}
	}

	private void start(String sfile) {
		if (State.hashType.length() > 0) {
			State.running = true;
			State.hashCode = "";
			final String file = sfile;
			EventQueue.invokeLater(new Runnable() {
				@Override
				public void run() {
					logField.append("FILE:\r\n");
					logField.append(file);
					logField.append("\r\n");
				}
			});

			Thread thread = new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						State.hashCode = hash.hashFile(file, State.hashType);
						EventQueue.invokeLater(new Runnable() {
							@Override
							public void run() {
								if (State.hashCode.length() > 0) {
									logField.append(State.hashType
											.toUpperCase());
									logField.append(":\r\n");
									logField.append(State.hashCode);
									logField.append("\r\n\r\n");
									JOptionPane
											.showMessageDialog(HashFile.this,
													"The hash code has been generated!");
								}
							}
						});

					} catch (NoSuchAlgorithmException | DigestException
							| IOException e) {
						State.running = false;
						State.hashCode = "";
						State.hashCode = "";
						e.printStackTrace();
					}
				}
			});
			thread.start();
		}
	}

	@Override
	public void stateChanged(ChangeEvent event) {
		if (false == State.running) {
			JRadioButton source = (JRadioButton) event.getSource();
			String command = source.getActionCommand();
			switch (command) {
			case "md5":
				radSHA1.setSelected(false == radMd5.isSelected());
				break;
			case "sha1":
				radMd5.setSelected(false == radSHA1.isSelected());
				break;
			}
		}

	}

	private JTextArea logField;
	private JTextField pathField;
	private JButton btnStart;
	private JButton btnCopy;
	private JButton btnBrowse;
	private JProgressBar progressBar;
	private JFileChooser fileChoose;
	private JRadioButton radMd5;
	private JRadioButton radSHA1;

	@Override
	public void dragEnter(DropTargetDragEvent dtde) {

		if (false == State.running) {
			dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
		}
	}

	@Override
	public void dragOver(DropTargetDragEvent dtde) {

	}

	@Override
	public void dropActionChanged(DropTargetDragEvent dtde) {

	}

	@Override
	public void dragExit(DropTargetEvent dte) {
		// TODO Auto-generated method stub

	}

	@Override
	public void drop(DropTargetDropEvent event) {
		if (false == State.running) {
			event.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
			Transferable tr = event.getTransferable();
			DataFlavor[] flavors = tr.getTransferDataFlavors();
			for (int i = 0; i < flavors.length; i++) {
				DataFlavor flavor = flavors[i];
				if (flavor.match(DataFlavor.javaFileListFlavor)) {
					try {
						Object obj = tr.getTransferData(flavor);
						@SuppressWarnings("unchecked")
						List<File> list = (List<File>) obj;
						File file = list.get(0);
						final String path = file.getAbsolutePath();
						EventQueue.invokeLater(new Runnable() {

							@Override
							public void run() {
								pathField.setText(path);
								State.hashType = radMd5.isSelected() ? "md5"
										: "sha1";
								String path = pathField.getText();
								if (path.length() > 0) {
									start(path);
								}
							}
						});
					} catch (UnsupportedFlavorException | IOException e) {
						e.printStackTrace();
					}
					break;
				}
			}
			event.dropComplete(true);
		}
	}
}
